package common

import (
	"github.com/dgrijalva/jwt-go"
	"hobby-mate/middleware/globalLogger"
	"time"
)

type UserBaseInfo struct {
	Username  string
	AccountId string
}

// Claims 结构用于创建 JWT 声明
type Claims struct {
	UserBaseInfo
	jwt.StandardClaims
}

var (
	// 签名
	jwtKey = []byte("treeRoot")
	// 过期时间
	expirationTime = time.Now().Add(24 * time.Hour)
)

// GenerateToken 生成token
func GenerateToken(username string, accountId string) (string, error) {
	userBaseInfo := UserBaseInfo{
		Username:  username,
		AccountId: accountId,
	}
	claims := &Claims{
		UserBaseInfo: userBaseInfo,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expirationTime.Unix(),
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenString, err := token.SignedString(jwtKey)
	if err != nil {
		globalLogger.Error(map[string]interface{}{"generate token failed": err.Error()})
		return "", err
	}
	return tokenString, nil
}

// RefreshToken 刷新token
func RefreshToken(tokenString string) (string, error) {
	claims := &Claims{}
	_, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
		return jwtKey, nil
	})
	if err != nil {
		globalLogger.Error(map[string]interface{}{"refresh token failed": err.Error()})
		return "", err
	}
	if time.Unix(claims.ExpiresAt, 0).Sub(time.Now()) > 30*time.Second {
		return "", nil
	}
	claims.ExpiresAt = expirationTime.Unix()
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	tokenString, err = token.SignedString(jwtKey)
	if err != nil {
		globalLogger.Error(map[string]interface{}{"refresh token failed": err.Error()})
		return "", err
	}
	return tokenString, nil
}

// CheckToken 检查token是否为本签名、是否过期
func checkToken(tokenString string) (bool, error) {
	claims := &Claims{}
	_, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
		return jwtKey, nil
	})
	if err != nil {
		globalLogger.Error(map[string]interface{}{"check token failed": err.Error()})
		return false, err
	}
	if claims.ExpiresAt < time.Now().Unix() {
		return false, nil
	}
	return true, nil
}

// ParseToken 解析token 获取Claims中的Username和AccountId
func parseToken(tokenString string) (*UserBaseInfo, error) {
	claims := &Claims{}
	userBaseInfo := &UserBaseInfo{}
	token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
		return jwtKey, nil
	})
	if err != nil {
		globalLogger.Error(map[string]interface{}{"parse token failed": err.Error()})
		return userBaseInfo, err
	}
	if token.Valid {
		userBaseInfo.Username = claims.Username
		userBaseInfo.AccountId = claims.AccountId
		return userBaseInfo, nil
	}
	return userBaseInfo, err
}

// CheckAndParseToken 校验并解析token返回用户信息
func CheckAndParseToken(tokenString string) (*UserBaseInfo, error) {
	isValid, err := checkToken(tokenString)
	if err != nil {
		return nil, err
	}
	if !isValid {
		return nil, nil
	}
	userBaseInfo, err := parseToken(tokenString)
	if err != nil {
		return nil, err
	}
	return userBaseInfo, nil
}
